/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.community.component.spreadsheet;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import org.controlsfx.control.spreadsheet.GridBase;
import org.controlsfx.control.spreadsheet.SpreadsheetCell;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据表控件
 * @author zpy
 * @version 1.0.0
 */
public abstract class TableSheetView<T> extends BaseSheetView {
    protected final static Integer DEFAULT_EMPTY_DATA_COUNT = 100;
    protected final static Integer DEFAULT_APPEND_DATA_COUNT = 20;
    protected final static Integer MIN_EMPTY_DATA_COUNT = 3;

    protected List<T> sheetData;

    public void loadContent(List<T> data){
        this.editModel.set(false);
        this.sheetData = data;
        this.clearContent();
        for(var dataIndex=0;dataIndex<data.size();dataIndex++){
            this.loadContent(data.get(dataIndex),toSheetRowIndex(dataIndex));
        }
        this.editModel.set(true);
    }

    protected abstract void loadContent(T info,Integer sheetRowIndex);

    public boolean validate(){
        boolean validResult = true;
        for(var sheetRowIndex=0;sheetRowIndex<this.getGrid().getRows().size();sheetRowIndex++){
            if(isEmptyData(sheetRowIndex)){
                continue;
            }
            var rowData = this.getGrid().getRows().get(sheetRowIndex);
            if(validResult){
                validResult = this.validate(rowData);
            }else{
                this.validate(rowData);
            }
        }
        return validResult;
    }


    public void clearValidate(){
        this.getGrid().getRows().forEach(this::clearValidate);
    }

    protected void clearContent(){
        this.getGrid().getRows().forEach(row->{
            clearValidate(row);
            row.forEach(cell->{
                if(cell.isEditable()){
                    cell.setItem("");
                }
            });
        });
    }

    protected void buildGrid(GridBase grid, Integer dataCount){
        ObservableList<ObservableList<SpreadsheetCell>> rows = FXCollections.observableArrayList();
        for(var dataIndex=0;dataIndex<dataCount;dataIndex++){
            rows.add(generateEmptyDataRow(dataIndex));
        }
        grid.setRows(rows);
    }

    protected void checkAndAppendEmptyDataRow(Integer currentSheetRowIndex){
        if((this.getGrid().getRows().size() - currentSheetRowIndex)<MIN_EMPTY_DATA_COUNT){
            this.appendEmptyDataRow();
        }
    }

    protected void appendEmptyDataRow(){
        AtomicInteger sheetRowIndex = new AtomicInteger(this.getGrid().getRows().size());
        for(var index = 0;index<DEFAULT_APPEND_DATA_COUNT;index++){
            this.getGrid().getRows().add(generateEmptyDataRow(sheetRowIndex.getAndIncrement()));
        }
    }

    /**
     * 验证数据内容
     * @param rowData 表行数据
     * @return 验证结果
     */
    protected abstract boolean validate(ObservableList<SpreadsheetCell> rowData);

    /**
     * 清除验证失败标记
     * @param rowData 表行数据
     */
    protected abstract void clearValidate(ObservableList<SpreadsheetCell> rowData);

    /**
     * 是否空数据行
     * @param sheetRowIndex 表行号
     * @return 是否空数据行
     */
    protected abstract boolean isEmptyData(Integer sheetRowIndex);

    /**
     * 数据列
     * @return 数据列标题
     */
    protected abstract List<String> getDataColumns();

    /**
     * 生成空数据行
     * @param rowIndex 空数据行号
     * @return 空数据单元格列表
     */
    protected abstract ObservableList<SpreadsheetCell> generateEmptyDataRow(int rowIndex);

}